import React, { Component } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import cn from 'classnames';
import './index.less';
import { Empty, Icon } from 'antd';

function filterOptions(options = [], search = '', fieldNames = {}) {
  const { label: labelField = 'label', children: childrenField = 'children' } = fieldNames;

  const filtered = [];

  for (let option of options) {
    if (_.get(option, [childrenField, 'length'])) {
      option[childrenField] = filterOptions(option[childrenField], search, fieldNames);
    }

    if (
      _.includes(_.toLower(option[labelField]), _.toLower(search)) ||
      _.get(option, [childrenField, 'length'])
    ) {
      filtered.push(option);
    }
  }
  return filtered;
}

function groupOptions(options = [], search = '', path = [], fieldNames = {}) {
  const filteredOptions = filterOptions(_.cloneDeep(options), search, fieldNames);
  const { value: valueField = 'value', children: childrenField = 'children' } = fieldNames;
  filteredOptions.forEach(option => (option.$path = [option[valueField]]));
  const grouped = [filteredOptions];

  const $path = [];
  for (const key of path) {
    $path.push(key);
    const current = _.find(grouped[grouped.length - 1], item => item[valueField] === key);
    const children = _.get(current, childrenField, []);
    if (children.length) {
      children.map(option => (option.$path = $path.concat(option[valueField])));
      grouped.push(children);
    } else {
      break;
    }
  }
  return grouped;
}

class CascaderUl extends Component {
  static propTypes = {
    value: PropTypes.array,
    options: PropTypes.array,
    search: PropTypes.string,
    fieldNames: PropTypes.array,
    onChange: PropTypes.func,
    addEmptySearch: PropTypes.bool
  };

  constructor(props) {
    super(props);
    this.state = {
      path: []
    };
  }

  onMouseMove = e => {
    const path = _.get(e, 'target.dataset.path', '')
      .split(',')
      .filter(Boolean);
    if (path.length) {
      this.setState({ path: path });
    }
  };
  onMouseDown = e => {
    e.preventDefault();
    e.stopPropagation();
    const value = _.get(e, 'target.dataset.value', '');
    if (value) {
      this.props.onChange(value);
    }
  };
  renderEmpty = () => {
    const { addEmptySearch = true, search } = this.props;
    if (addEmptySearch && search) {
      return (
        <ul className="group new-add-group">
          <li className="item" data-value={search}>
            {search}&nbsp;<span className="new-add">(新增)</span>
          </li>
        </ul>
      );
    } else {
      return (
        <Empty
          description={'暂无数据'}
          image={Empty.PRESENTED_IMAGE_SIMPLE}
          style={{ width: '100%' }}
        />
      );
    }
  };
  render() {
    const { value = [], options: rawOptions, search, fieldNames } = this.props;
    const {
      label: labelField = 'label',
      value: valueField = 'value',
      children: childrenField = 'children'
    } = fieldNames;
    const { path } = this.state;
    const groupedOptions = groupOptions(rawOptions, search, path, fieldNames);
    const noData = !_.get(groupedOptions, [0, 'length']);
    return (
      <div
        className={cn('cascader-ul', { 'no-data': noData })}
        onMouseMove={this.onMouseMove}
        onMouseDown={this.onMouseDown}
      >
        {noData
          ? this.renderEmpty()
          : groupedOptions.map((options, gIndex) => (
              <ul key={path[gIndex - 1] || gIndex} className="group">
                {options.map(option => {
                  const optionValue = option[valueField];
                  const more = _.get(option, [childrenField, 'length']);
                  const selected = _.includes(value, optionValue);
                  return (
                    <li
                      className={cn('item', {
                        more,
                        active: path.includes(optionValue),
                        selected
                      })}
                      key={optionValue}
                      data-value={more ? '' : optionValue}
                      data-path={option.$path.join(',')}
                    >
                      {option[labelField]}
                      {selected && <Icon type="check" className="checked-icon" />}
                    </li>
                  );
                })}
              </ul>
            ))}
      </div>
    );
  }
}

export default CascaderUl;
